#include <iostream>
#include <functional>
#include <vector>
#include <string>

// Explicit instantiation of std::string needed, otherwise
// we get a liner error with clang on osx thats a bug in libc++
// because of interaction with
// __attribute__ ((__visibility__("hidden"), __always_inline__)) in std::string
// Without this line, &std::string::empty will be in error of 'undefined symbols'
template class std::basic_string<char>;

class Screen {
public:
    using Action = Screen& (Screen::*) ();
    enum Directions { HOME, FORWARD, BACK, UP, DOWN };

    Screen& home() {
        std::cout << "go to home\n";
        return *this;
    }
    Screen& forward() {
        std::cout << "go to forward\n";
        return *this;
    }
    Screen& back() {
        std::cout << "go to back\n";
        return *this;
    }
    Screen& up() {
        std::cout << "go to up\n";
        return *this;
    }
    Screen& down() {
        std::cout << "go to down\n";
        return *this;
    }

    Screen& move(Directions);
private:
    static Action menu[];
};

Screen& Screen::move(Directions cm)
{
    return (this->*menu[cm])();
}

Screen::Action Screen::menu[] = {
    &Screen::home,
    &Screen::forward,
    &Screen::back,
    &Screen::up,
    &Screen::down,
};

int main()
{
    Screen myScreen;
    myScreen.move(Screen::HOME);
    myScreen.move(Screen::UP);

    std::function<bool (const std::string&)> fcn = &std::string::empty;
    std::function<bool (const std::string*)> fp = &std::string::empty;

    // The callable generated by mem_fn can be called on either an object or
    // a pointer:
    std::vector<std::string> svec{"", "second"};
    auto f = std::mem_fn(&std::string::empty);
    f(*svec.begin());
    if (f(&svec[0])) {
        std::cout << "first element of svec is empty.\n";
    }

    // std::bind
    using std::placeholders::_1;
    auto fb = std::bind(&std::string::empty, _1);
    if (fb(*svec.begin())) {
        std::cout << "first element of svec is empty (bind).\n";
    }
    f(&svec[0]);

    return 0;
}
